let utils = require('./BleUtils.js')
class BleSDK {
	static STATUS_ACTIONS = [
		['10000', () => { utils.showStatusTips('未初始化蓝牙适配器') }],
		['10001', () => { utils.showStatusTips('请检查蓝牙是否开启') }],
		['10002', () => { utils.showStatusTips('未找到设备') }],
		['10003', () => { utils.showStatusTips('连接失败') }],
		['10004', () => { utils.showStatusTips('没有找到指定服务') }],
		['10005', () => { utils.showStatusTips('没有找到指定特征值') }],
		['10006', () => { utils.showStatusTips('当前连接已断开') }],
		['10007', () => { utils.showStatusTips('当前特征值不支持此操作') }],
		['10008', () => { utils.showStatusTips('其余所有系统上报的异常') }],
		['10009', () => { utils.showStatusTips('系统版本低，不支持蓝牙') }],
		['100010', () => { utils.showStatusTips('已连接') }],
		['100011', () => { utils.showStatusTips('配对设备需要配对码') }],
		['100012', () => { utils.showStatusTips('连接超时，请重试') }],
		['100013', () => { utils.showStatusTips('连接 deviceId 为空或者是格式不正确') }],
		['default', () => {}]
	]
	static BLUE_STATUS_FAILED = 0
	static BLUE_STATUS_SUCCEED = 1
	static BLUE_SERVICE_FAILED = 2

	constructor(options) {
		console.log('options: ', options)
		// 蓝牙错误状态
		this.statusActions = new Map(BleSDK.STATUS_ACTIONS) || options.statusActions
		// 设备mac
		this.mac = options?.mac || ''
		// 蓝牙设备id
		this.deviceId = options?.deviceId || ''
		// 蓝牙设备
		this.device = {}
		// uuid
		this.serviceId = options?.serviceId
		// 订阅
		this.notify = options?.notify
		// 通知特征
		this.notifyCharaterId = ''
		// 读取服务
		this.readServicesId = ''
		// 读取特征
		this.readCharaterId = ''
		// 写入服务
		this.writeServicesId = ''
		// 写入特征
		this.writeCharaterId = ''
		// 写入的值
		this.writeValue = ''
		// 写入延迟
		this.writeSleep = options?.writeSleep || 40
		// 统一回调
		this.bleStatusCallBack = options.bleStatusCallBack
		this.status = BleSDK.BLUE_STATUS_SUCCEED
		this.bleStatusCallBack(this.status)
		// 重写次数
		this.rewriteTimes = 0
		// 重连次数
		this.connectTimes = 0
		// 写入的值
		this.hexValue = ''
		// 定时器
		this.timer = null
	}

	statusToast(status) {
		let action = this.statusActions.get(`${status}`) || this.statusActions.get('default')
		action.call(this)
	}

	// 初始化蓝牙模块
	openBluetoothAdapter() {
		return new Promise((resolve, reject) => {
			wx.openBluetoothAdapter({
				success: (res) => {
					console.log('初始化成功')
					resolve(true)
				},
				fail: async (err) => {
					console.log('打开蓝牙适配器失败：', err.code)
					this.statusToast(err.code)
					this.status = BleSDK.BLUE_SERVICE_FAILED
					this.bleStatusCallBack(this.status)
					reject(err)
				}
			})
		})
	}

	// 关闭蓝牙模块。调用该方法将断开所有已建立的连接并释放系统资源。建议在使用蓝牙流程后，与 openBluetoothAdapter 成对调用
	closeBluetoothAdapter() {
		return new Promise((resolve, reject) => {
			wx.closeBluetoothAdapter({
				success: (res) => {
					console.log('关闭初始化成功', this.device)
					resolve(true)
				},
				fail: (err) => {
					console.log('关闭蓝牙设配器失败：', err.code)
					reject(err)
				}
			})
		})
	}

	// 获取本机蓝牙适配器状态
	getBluetoothAdapterState() {
		return new Promise((resolve, reject) => {
			wx.getBluetoothAdapterState({
				success: (res) => {
					resolve(res.available)
					console.log('本机蓝牙状态: ', res)
				},
				fail: (err) => {
					console.log('获取蓝牙设配器失败：', err.code)
					this.statusToast(err.code)
					this.status = BleSDK.BLUE_SERVICE_FAILED
					this.bleStatusCallBack(this.status)
					reject(err)
				}
			})
		})
	}

	// 开始搜寻附近的蓝牙外围设备。此操作比较耗费系统资源，请在搜索并连接到设备后调用 stopBluetoothDevicesDiscovery 方法停止搜索
	startBluetoothDevicesDiscovery() {
		return new Promise((resolve, reject) => {
			wx.startBluetoothDevicesDiscovery({
				allowDuplicatesKey: false,
				powerLevel: 'high',
				success: (res) => {
					console.log('开始搜索: ', res)
					resolve(true)
				},
				fail: (err) => {
					console.log('搜索蓝牙设备失败：', err.code)
					this.statusToast(err.code)
					this.status = BleSDK.BLUE_STATUS_FAILED
					this.bleStatusCallBack(this.status)
					reject(err)
				}
			})
		})
	}

	// 停止搜寻附近的蓝牙外围设备。若已经找到需要的蓝牙设备并不需要继续搜索时，建议调用该接口停止蓝牙搜索。
	stopBluetoothDevicesDiscovery() {
		return new Promise((resolve, reject) => {
			wx.stopBluetoothDevicesDiscovery({
				success: (res) => {
					console.log('已停止搜索')
					resolve(true)
				},
				fail: (err) => {
					console.log('停止搜索蓝牙失败', err.code)
					reject(err)
				}
			})
		})
	}

	// 监听寻找到新设备的事件，必须在 startBluetoothDevicesDiscovery 成功后调用
	onBluetoothDeviceFound() {
		return new Promise((resolve, reject) => {
			// 6秒后未找到设备返回空对象, 表示没找到
			this.timer = setTimeout(async () => {
				resolve({})
			}, 6 * 1000)

			// 找到设配返回出去
			wx.onBluetoothDeviceFound(async (res) => {
				if (res.devices && res.devices.length > 0) {
					console.log('res.devices: ', res.devices[0].name, this.mac)
					if (res.devices[0].name == this.mac) {
						await this.stopBluetoothDevicesDiscovery()
						console.log('搜索到对应设备-------->', res.devices[0])
						clearTimeout(this.timer)
						resolve(res.devices[0])
					}
				}
			})
		})
	}

	// 连接低功耗蓝牙设备
	createBLEConnection(deviceId) {
		return new Promise((resolve, reject) => {
      if (deviceId) this.deviceId = deviceId
      console.log('开始连接', this.deviceId)
			wx.createBLEConnection({
				deviceId: this.deviceId,
				success: (res) => {
					setTimeout(() => {
						resolve(true)
					}, 1800)
				},
				fail: (err) => {
          console.log('连接蓝牙失败：', err.code)
          wx.showToast({ title: '连接蓝牙失败，退出页面重试', icon: 'none' })
					reject(false)
				}
			})
		})
	}

	// 断开蓝牙连接
	closeBLEConnection() {
		return new Promise((resolve, reject) => {
			wx.closeBLEConnection({
				deviceId: this.deviceId,
				success: (res) => {
					console.log('断开蓝牙连接成功')
					resolve(res)
				},
				fail: (err) => {
          console.log('断开蓝牙连接失败：', err.code)
          wx.hideLoading()
					reject(err)
				}
			})
		})
	}

	// 获取蓝牙设备所有服务
	getBLEDeviceServices() {
		return new Promise((resolve, reject) => {
			wx.getBLEDeviceServices({
				deviceId: this.deviceId,
				success: (res) => {
					resolve(res)
				},
				fail: async (err) => {
					console.log('获取设备服务失败: ', err.code)
					reject(false)
				}
			})
		})
	}

	// 获取蓝牙设备某个服务中所有特征值(characteristic)。
	getBLEDeviceCharacteristics(servicesList) {
    console.log('servicesList', servicesList)
		return new Promise(async (resolve, reject) => {
			let services = servicesList.services
			for (let servicesItem of services) {
				if (servicesItem.uuid != this.serviceId) {
					continue
				}
				const res = await wx.getBLEDeviceCharacteristics({
					deviceId: this.deviceId,
					serviceId: servicesItem.uuid
        })
        console.log('servicesItem.uuid', servicesItem.uuid)
        console.log('characteristics res', res)
				const characteristics = res.characteristics
				for (let characteristicsItem of characteristics) {
					// 记录通知特征值
					if (characteristicsItem.properties.notify) {
						this.notifyCharaterId = characteristicsItem.uuid
						this.notifyBLECharacteristicValueChange(this.deviceId, servicesItem.uuid, characteristicsItem.uuid)
					}
					// 记录读取特征值
					if (characteristicsItem.properties.read) {
						this.readCharaterId = characteristicsItem.uuid
						this.readServicesId = servicesItem.uuid
					}
					// 记录写入特征值
					if (characteristicsItem.properties.write) {
						this.writeCharaterId = characteristicsItem.uuid
						this.writeServicesId = servicesItem.uuid
					}
				}
				if (this.writeServicesId != null && this.writeServicesId != '' && this.writeServicesId != undefined) {
					setTimeout(() => {
						resolve(true)
					}, 100)
					return
				} else {
					this.status = BleSDK.BLUE_STATUS_FAILED
					this.bleStatusCallBack(this.status)
					resolve(false)
				}
			}
		})
	}

	// 启用低功耗蓝牙设备特征值变化时的 notify 功能，订阅特征值。注意：必须设备的特征值支持 notify 或者 indicate 才可以成功调用。
	// 另外，必须先启用 notifyBLECharacteristicValueChange 才能监听到设备 characteristicValueChange 事件
	notifyBLECharacteristicValueChange(deviceId, serviceId, charaterId) {
		wx.notifyBLECharacteristicValueChange({
			deviceId: deviceId,
			serviceId: serviceId,
			characteristicId: charaterId,
			state: true,
			success: (r) => {
				console.log('获取特征值成功: ', r)
				if (this.notify) {
					wx.onBLECharacteristicValueChange((res) => {
						if (res.value) {
							const strValue = utils.arrayBuffer2HexString(res.value)
							console.log('接收到设备数据', strValue)
							this.notify(strValue)
						}
					})
				}
			},
			fail: (err) => {
				console.log('获取特征值失败：', err.code)
				this.statusToast(err.code)
				this.status = BleSDK.BLUE_STATUS_FAILED
				this.bleStatusCallBack(this.status)
			}
		})
	}

	// 写入值
	writeValueToBLE(value) {
		return new Promise(async (resolve, reject) => {
			console.log('writeValue: ', value)
			this.hexValue = value
			if (!this.writeBytes || this.writeBytes <= 0) {
				let bufferValue = utils.hexString2ArrayBuffer(value.toUpperCase())
				this.writeValue = await this.writeBLECharacteristicValue(bufferValue, resolve, reject)
				return
			}
			if (value.length == 0) return
			let charLength = this.writeBytes * 2
			let index = parseInt(value.length / charLength)
			if (value.length % charLength != 0) index = index + 1
			for (let k = 0; k < index; k++) {
				let send_str = value.substring(k * charLength, k * charLength + charLength)
				let bufferValue = utils.hexString2ArrayBuffer(send_str.toUpperCase())
				this.writeValue = await this.writeBLECharacteristicValue(bufferValue, resolve, reject)
				utils.sleep(this.writeSleep)
			}
		})
	}

	// 向低功耗蓝牙设备特征值中写入二进制数据。注意：必须设备的特征值支持 write 才可以成功调用。
	writeBLECharacteristicValue(value, resolve, reject) {
		wx.writeBLECharacteristicValue({
			// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
			deviceId: this.deviceId,
			// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
			serviceId: this.writeServicesId,
			// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
			characteristicId: this.writeCharaterId,
			// 这里的value是ArrayBuffer类型
			value,
			success: (res) => {
				console.log('writeBLECharacteristicValue 成功', JSON.stringify(res))
				resolve(true)
			},
			fail: (err) => {
				console.log('写入失败的数据wrteValue：' + utils.arrayBuffer2HexString(value), err)
				reject(false)
			}
		})
	}

	writeValueByTimes(value) {
		return new Promise(async (resolve, reject) => {
			try {
				let isWriteSucceed = await this.writeValueToBLE(value)
				console.log('isWriteSucceed', isWriteSucceed)
				resolve(isWriteSucceed)
			} catch (err) {
				console.log(err)
				if (this.connectTimes < 2) {
					this.connectTimes++
					await this.closeBLEConnection()
					let isConnected = await this.handleInitToBLEConnection()
					let isWriteSucceed = await this.writeValueToBLE(value)
					resolve(isWriteSucceed)
				} else {
					this.status = BleSDK.BLUE_SERVICE_FAILED
					this.bleStatusCallBack(this.status)
					this.connectTimes = 0
					this.device = {}
					// 如果重连后失败了, 直接返回false
					resolve(false)
				}
			}
		})
	}

	// 设备查询情况处理
	handleDeviceFound() {
		return new Promise(async (resolve, reject) => {
			// 如果没有mac（或设备蓝牙id）停止搜索
			if (!this.mac) {
				await this.stopBluetoothDevicesDiscovery()
				this.statusToast('100013')
				return
			}
			// 查找蓝牙设备
			this.device = await this.onBluetoothDeviceFound()
			// 如果没找到设备, 顺带断开蓝牙
			if (Object.keys(this.device).length == 0) {
				await this.closeBluetoothAdapter()
				resolve(false)
				return
			}
			// 如果存在匹配的设备，返回出去
			this.deviceId = this.device.deviceId
			// 找到设备清除定时器
			clearTimeout(this.timer)
			resolve(true)
		})
	}

	// 初始化到连接操作
	handleInitToBLEConnection() {
		return new Promise(async (resolve, reject) => {
			// 无论如何，先关闭适配器再打开
			await this.closeBluetoothAdapter()
			await this.openBluetoothAdapter()
			// 没有设备信息才去搜索
			if (Object.keys(this.device).length == 0) {
				await this.startBluetoothDevicesDiscovery()
				let isDeviceFound = await this.handleDeviceFound()
				// 如果没找到设备就不连接
				if (!isDeviceFound) {
					wx.hideLoading()
					resolve(false)
					return
				}
			}
			// 找到设备后开始连接
			let isConnected = await this.handleConnectBLE()
			resolve(isConnected)
		})
	}

	// 连接蓝牙机制
	handleConnectBLE() {
		return new Promise(async (resolve, reject) => {
			try {
				// 连接蓝牙
				let isConnected = await this.createBLEConnection(this.deviceId)
				console.log('isConnected: ', isConnected)
				// 获取设备服务
				let servicesList = await this.getBLEDeviceServices()
				// 获取设备状态码
				let characteristics = await this.getBLEDeviceCharacteristics(servicesList)
				resolve(characteristics)
			} catch (err) {
				// 从开始连接蓝牙开始, 到写入信息之前, 任何一步失败了都断开蓝牙的全部操作, 重新连接一次, 三次太久了
				await this.closeBLEConnection()
				await this.closeBluetoothAdapter()
				if (this.connectTimes == 0) {
					this.connectTimes++
					let res = await this.handleInitToBLEConnection()
					resolve(res)
				} else {
					this.status = BleSDK.BLUE_SERVICE_FAILED
					this.bleStatusCallBack(this.status)
					this.device = {}
					this.connectTimes = 0
					// 如果重连后失败了, 直接返回false
					resolve(false)
				}
			}
		})
	}

	// 初始化到查找操作
	handleInitToBLEFound() {
		return new Promise(async (resolve, reject) => {
			// 无论如何，先关闭适配器再打开
			await this.closeBluetoothAdapter()
			await this.openBluetoothAdapter()
			// 没有设备信息才去搜索
			await this.startBluetoothDevicesDiscovery()
			let isDeviceFound = await this.handleDeviceFound()
			// 如果没找到设备就不连接
			if (!isDeviceFound) {
				wx.hideLoading()
				resolve({})
				return
			}
			console.log('this.device: ', this.device)
			resolve(this.device)
		})
	}
}

export default BleSDK
